package com.jack.screenprojectionplayersimple

import android.R.attr
import android.annotation.SuppressLint
import android.media.MediaCodec
import android.media.MediaFormat
import android.os.Bundle
import android.util.DisplayMetrics
import android.view.Surface
import android.view.SurfaceHolder
import android.view.SurfaceView
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import java.net.URI
import java.nio.ByteBuffer


class MainActivity : AppCompatActivity(), SocketCallback {
    @SuppressLint("MissingInflatedId")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val surface = findViewById<View>(R.id.preview) as SurfaceView

        val displayMetrics = DisplayMetrics()
        windowManager.defaultDisplay.getMetrics(displayMetrics)
        val screenWidth = displayMetrics.widthPixels
        val screenHeight = displayMetrics.heightPixels
        val surfaceHolder = surface.holder
        surfaceHolder.addCallback(object : SurfaceHolder.Callback {
            override fun surfaceCreated(holder: SurfaceHolder) {
                initClientSocket()
                initMediaCodec(screenWidth, screenHeight, holder.surface)
            }

            override fun surfaceChanged(
                holder: SurfaceHolder,
                format: Int,
                width: Int,
                height: Int
            ) {
            }

            override fun surfaceDestroyed(holder: SurfaceHolder) {}
        })
    }

    private fun initClientSocket() {
        val uri = URI("ws://192.168.1.4:9999")
        val clientSocket = ClientSocket(this)
        clientSocket.init(uri)
    }

    private lateinit var mMediaCodec: MediaCodec
    fun initMediaCodec(width: Int, height: Int, surface: Surface) {
        //1.创建MediaCodec
        mMediaCodec = MediaCodec.createDecoderByType(MediaFormat.MIMETYPE_VIDEO_HEVC)
        //2.1.mediaformat:用于指定媒体格式，包括音视频的编码格式、采样率、帧率等信息。它描述了输入数据的格式，以便编解码器能够正确地处理数据。
        val mediaformat =
            MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_HEVC, width, height)
        mediaformat.setInteger(MediaFormat.KEY_FRAME_RATE, 15)
        //2.配置编解码器的参数
        //2.2.参数2：该参数用于指定一个Surface对象，如果你想在解码过程中将解码后的视频帧渲染到屏幕上，
        // 可以通过这个Surface进行渲染。如果你只是进行音频解码，可以将此参数设置为null。
        //2.3.参数3：如果你需要对音视频进行数字版权管理（DRM）或其他加密操作，可以通过这个参数传递相应的MediaCrypto对象。如果不需要加密，可以将此参数设置为null。
        //2.4.参数4：将 flags 设置为 0 表明不启用任何附加的特性或标志，仅使用默认的配置。
        //通过设置 CONFIGURE_FLAG_ENCODE 来表示这是一个编码器，或者设置 CONFIGURE_FLAG_SECURE 来表示需要安全的解码。但如果没有这些特殊需求，通常可以将 flags 参数保持为 0。
        mMediaCodec.configure(mediaformat, surface, null, 0)
        mMediaCodec.start()
    }

    override fun callBack(data: ByteArray) {
        println("CustomWebSocketClient callBack ${data.size}")
        //3.解码
        //如果在指定的时间没有查询出可用的ByteBuffer，就返回-1
        val index = mMediaCodec.dequeueInputBuffer(10000)

        if (index >= 0) {
            val inputBuffer: ByteBuffer? = mMediaCodec.getInputBuffer(index)
            //3.1..根据索引找到对应的ByteBuffer
            inputBuffer?.let {
                //3.2.执行清空的操作
                inputBuffer.clear()
                inputBuffer.put(data, 0, data.size)

                //3.3.通知dsp芯片进行解码
                //参数1：要放入的输入缓冲区的索引
                //参数2：输入数据在输入缓冲区中的偏移量。通常，可以设置为 0，表示从输入数据的起始位置开始。
                //参数3：表示输入数据的大小，即要放入输入缓冲区的数据的字节数
                //参数4：表示输入数据的展示时间戳，以微秒为单位。对于视频来说，它通常是视频帧的显示时间；对于音频来说，它通常是音频样本的播放时间。
                //可以通过调整时间戳来实现对播放速度的控制
                //参数5：表示输入数据的标志位，用于指定一些特殊的处理要求。常见的标志位包括：
                //BUFFER_FLAG_KEY_FRAME: 表示关键帧。
                //BUFFER_FLAG_END_OF_STREAM: 表示输入流结束。
                //传入0，表示没有特殊的标志或配置，即不启用任何额外的特性。
                mMediaCodec.queueInputBuffer(index, 0, data.size, System.currentTimeMillis(), 0)
            }
        }

        val bufferInfo = MediaCodec.BufferInfo()
        //4.（从输出缓冲区队列中获取可用的输出缓冲区索引）获取解码后的数据，以便应用程序可以进一步处理或渲染。
        //4.1.在参数2时间内没有获取到就返回-1     dequeueOutputBuffer方法的设计有些不太一样
        //4.2.参数1：一个 MediaCodec.BufferInfo 对象，用于存储输出缓冲区的相关信息，例如数据的大小、时间戳等。
        var outputBufferIndex: Int = mMediaCodec.dequeueOutputBuffer(bufferInfo, 100000)

        while (outputBufferIndex > 0) {
            //5.解码器的输出缓冲区中包含解码后的音视频数据。应用程序可以根据具体的需求，将这些数据用于播放、存储或其他后续处理。在处理完数据后，
            // 需要调用 releaseOutputBuffer 方法来释放输出缓冲区，使其变为可用状态供下一次使用。
            //5.1.render 参数表示是否渲染该输出缓冲区的数据。如果设置为 true，表示渲染；如果设置为 false，则不进行渲染。
            mMediaCodec.releaseOutputBuffer(outputBufferIndex, true)
            outputBufferIndex = mMediaCodec.dequeueOutputBuffer(bufferInfo, 0)
        }
    }
}